home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Devices / How to Detect a CD / CD-ROM Detection / CDROMDetection.c < prev   
Encoding:
C/C++ Source or Header  |  1998-04-24  |  7.8 KB  |  273 lines  |  [TEXT/CWIE]

  1. // 
  2. // Apple Macintosh DTS
  3. // 
  4. // Sample code
  5. // 
  6. // by Brian Bechtel, WWDTS
  7. // 
  8. // File:        CDROMDetection.c
  9. // 
  10. // Copyright © 1998 Apple Computer, Inc.
  11. // All rights reserved.
  12. // 
  13. // You may incorporate this sample code into your applications
  14. // without restriction, though the sample code has been provided
  15. // "AS IS" and the responsibility for its operation is 100%
  16. // yours.  However, what you are not permitted to do is to
  17. // redistribute the source as "DTS Sample Code" after having made
  18. // changes. If you're going to re-distribute the source, we
  19. // require that you make it clear in the source that the code was
  20. // descended from DTS Sample Code, but that you've made
  21. // changes.
  22. //
  23.  
  24. #include <TextUtils.h>
  25. #include <LowMem.h>
  26. #include <DriverGestalt.h>
  27. #include <Files.h>
  28. #include <Devices.h>
  29. #include <SCSI.h>
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <SIOUX.h>        // Metrowerks only
  34.  
  35. // Be sure and put the #pragma options align=mac68k statement
  36. // around any structure definitions which require a particular
  37. // structure alignment; otherwise the compiler tries to word
  38. // align the definitions, and nothing works on the PowerPC side.
  39. #if PRAGMA_ALIGN_SUPPORTED
  40. #pragma options align=mac68k
  41. #endif
  42.  
  43. struct DeviceIdentParam {
  44.     QElemPtr                        qLink;
  45.     short                            qType;
  46.     short                            ioTrap;
  47.     Ptr                                ioCmdAddr;
  48.     IOCompletionUPP                    ioCompletion;
  49.     OSErr                            ioResult;
  50.     StringPtr                        ioNamePtr;
  51.     short                            ioVRefNum;
  52.     short                            ioCRefNum;
  53.     short                            csCode;
  54.     DeviceIdent                        deviceIdentification;
  55.     short                            csParam[9];
  56. };
  57. typedef struct DeviceIdentParam DeviceIdentParam, *DeviceIdentParamPtr;
  58.  
  59. #if PRAGMA_ALIGN_SUPPORTED
  60. #pragma options align=reset
  61. #endif
  62.  
  63. // This declares in C a type called "CallForEveryDriveQueueElement"
  64. // which can then be declared as a variable in some other routine.
  65. // That routine can initialize the variable to the address of some
  66. // routine to call, and pass that as a parameter to CruiseDriveQueue.
  67. typedef pascal OSErr (*CallForEveryDriveQueueElement)(DrvQElPtr dqPtr);
  68. // to use the above declaration, you would have code such as this:
  69. //        CallForEveryDriveQueueElement someCall = YourRoutineName;
  70. //        CruiseDriveQueue(someCall);
  71. // where "YourRoutineName" is replaced by the name of a routine
  72. // which has been declared as follows:
  73. //         pascal OSErr YourRoutineName(DrvQElPtr dqPtr);
  74. //
  75. // This is the declaration of the routine which cruises the drive
  76. // queue, calling the input parameter (a procedure) with each drive 
  77. // queue element in the drive queue.  It looks complicated, but
  78. // it winds up being much easier to use.
  79. pascal OSErr CruiseDriveQueue(CallForEveryDriveQueueElement theCall);
  80.  
  81. void            DetectCD(void);
  82. OSErr            DeviceIdentification(
  83.                     StringPtr drvrNamePtr, 
  84.                     DrvQElPtr dqPtr, 
  85.                     DeviceIdent *d);
  86. pascal OSErr    PrintDriverInformation(DrvQElPtr dqPtr);
  87. StringPtr        DrvrRefToName(short refNum);
  88. OSErr             DetermineUsingDriverGestalt(
  89.                     short driverRefNum,
  90.                     short driveNumber,
  91.                     OSType *deviceType);
  92.  
  93. //-----------------------------------------------------------------
  94. // The main routine.  Start here.  We turn off the annoying
  95. // "Do you want to save this window?" option of Metrowerks
  96. // Standard Libraries
  97. //
  98. void main(void)
  99. {
  100.     SIOUXSettings.asktosaveonclose = false;        // Metrowerks only
  101.     
  102.     printf ("Sample showing how to detect CD-ROM drives\n\n");
  103.  
  104.     DetectCD();
  105. }
  106.  
  107. //-----------------------------------------------------------------
  108. // This is the declaration of the routine which cruises the drive
  109. // queue, calling the input parameter (a procedure) with each drive
  110. // queue element in the drive queue.  It looks complicated, but it
  111. // winds up being easy to use.
  112. //
  113. pascal OSErr CruiseDriveQueue(CallForEveryDriveQueueElement theCall)
  114. {
  115.     register DrvQElPtr    dqPtr;
  116.     OSErr                err;
  117.  
  118.     dqPtr = (DrvQElPtr) GetDrvQHdr()->qHead;
  119.  
  120.     while (dqPtr != NULL) 
  121.     {
  122.         err = theCall(dqPtr);
  123.         if (err)
  124.             break;
  125.         dqPtr = (DrvQEl *) dqPtr->qLink;
  126.     }
  127.     return (err);
  128. }
  129.  
  130. //-----------------------------------------------------------------
  131. // This routine returns the device identification as documented 
  132. // in Designing PCI Cards and Drivers
  133. //
  134. OSErr    DeviceIdentification( StringPtr drvrNamePtr, 
  135.                               DrvQElPtr dqPtr, 
  136.                               DeviceIdent *d)
  137. {
  138.     DeviceIdentParam    pb = {0};
  139.     OSErr                err;
  140.     
  141.     pb.ioCompletion = nil;
  142.     pb.ioNamePtr = drvrNamePtr;
  143.     err = PBOpenSync((ParmBlkPtr)&pb);
  144.  
  145.     if (!err)
  146.     {
  147.         pb.ioVRefNum = dqPtr -> dQDrive;
  148.         pb.ioCRefNum = dqPtr -> dQRefNum;
  149.         pb.csCode = 120;
  150.         err = PBStatusSync((ParmBlkPtr)&pb);
  151.     }
  152.     *d = pb.deviceIdentification;
  153.     return err;
  154. }
  155.  
  156. //-----------------------------------------------------------------
  157. // This routine just sets up a variable with the name of a routine
  158. // to call for every drive queue element, and then calls our
  159. // generic "scan the drive queue" routine.  This will call the
  160. // routine we passed in for every drive queue element.
  161. // We tell the "CruiseDriveQueue" routine to call our 
  162. // PrintDriverInformation routine for each entry in the drive queue.
  163. void DetectCD(void)
  164. {
  165.     CallForEveryDriveQueueElement someCall = PrintDriverInformation;
  166.     CruiseDriveQueue(someCall);
  167. }
  168.  
  169. //-----------------------------------------------------------------
  170. // PrintDriverInformation prints information about the driver for
  171. // each Drive Queue Element we pass it.  If the drive in question
  172. // passes tests to see if it's a CD-ROM drive, we print additional
  173. // information
  174. //
  175. pascal OSErr PrintDriverInformation(DrvQElPtr dqPtr)
  176. {
  177.     StringPtr    drvrNamePtr;
  178.     OSType        theDriveType;
  179.     DeviceIdent    d;
  180.     OSErr        err;
  181.     
  182.     // dqPtr->dQRefNum contains the driver reference number.  
  183.     // In order to display something to the user, we will get
  184.     // the driver name by looking in the unit table (an array)
  185.     // to find the driver name.
  186.     drvrNamePtr = DrvrRefToName(dqPtr->dQRefNum);
  187.  
  188.     printf("DriverName: %.*s ", drvrNamePtr[0], &drvrNamePtr[1]);
  189.     if ( EqualString(drvrNamePtr, "\p.AppleCD", false, true) )
  190.         printf("(This is a CD-ROM drive.) ");
  191.     
  192.     err = DetermineUsingDriverGestalt(dqPtr->dQRefNum, dqPtr->dQDrive, &theDriveType);
  193.     if (!err)
  194.     {
  195.         char c[5];
  196.         BlockMoveData(&theDriveType, c, 4);
  197.         c[4] = 0;
  198.         printf("Driver Gestalt returned '%s'", c);
  199.     }
  200.     
  201.     err = DeviceIdentification(drvrNamePtr, dqPtr, &d);
  202.     if (!err)
  203.     {
  204.         printf("\nDevice reports that it is bus type %d, bus %d, target %d, partition/LUN %d.",
  205.             d.diReserved, d.bus, d.targetID, d.LUN);
  206.     }
  207.     printf("\n");
  208.     return noErr;
  209. }
  210.  
  211. //-----------------------------------------------------------------
  212. // Lookup driver name from the unit table. The driver name starts
  213. // at 18 bytes into the driver itself.  From the Unit Table entry
  214. // for this driver, get the name, but take into account whether it
  215. // is a handle based driver or a pointer based driver.
  216. //
  217. StringPtr DrvrRefToName(short refNum)
  218. {
  219.     AuxDCEHandle*        UTable  = (AuxDCEHandle*) LMGetUTableBase();
  220.     DCtlPtr                dctl;
  221.     Ptr                    p;
  222.     static StringPtr    driverName;
  223.     
  224.     if ( refNum == 0 )
  225.     {
  226.         driverName = "\p<none>";
  227.     }
  228.     else
  229.     {
  230.         dctl = (DCtlPtr) *UTable[~refNum];
  231.         p      =  dctl->dCtlDriver;
  232.         
  233.         // a RAMbased driver is handle based, a ROMbased driver
  234.         // is pointer based.  If it's a handle based driver, we
  235.         // need one more level of indirection.  The following 
  236.         // test provides that indirection if necessary.
  237.         if( dctl->dCtlFlags  & dRAMBasedMask) 
  238.             p = (void*) *p;
  239.  
  240.         if ( p != nil )
  241.             driverName = (void *)(p+18);
  242.         else
  243.             driverName = "\p-Purged-";
  244.     }
  245.     return  ( driverName);
  246. }
  247.  
  248. //-----------------------------------------------------------------
  249. // Call the driver using the DriverGestalt status code.  The result
  250. // tells us if this driver is a CD-ROM
  251. //
  252. OSErr DetermineUsingDriverGestalt(short driverRefNum, 
  253.                                   short driveNumber, 
  254.                                   OSType *deviceType)
  255. {
  256.     DriverGestaltParam    pb;
  257.     OSErr                err;
  258.     
  259.     pb.ioVRefNum             = driveNumber;
  260.     pb.ioCRefNum            = driverRefNum;
  261.     pb.csCode                 = kDriverGestaltCode;
  262.     pb.driverGestaltSelector = kdgDeviceType;
  263.     
  264.     err = PBStatusSync((ParmBlkPtr) &pb);
  265.     
  266.     if (!err)
  267.     {
  268.         *deviceType = pb.driverGestaltResponse;
  269.     }
  270.     return (err);
  271. }
  272.  
  273.